1   /*
2    *  Copyright 2015 the original author or authors. 
3    *  @https://github.com/scouter-project/scouter
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License"); 
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License. 
16   */
17  package scouter.util;
18  
19  import java.sql.Timestamp;
20  import java.text.ParseException;
21  import java.text.SimpleDateFormat;
22  import java.util.TimeZone;
23  
24  public class DateTimeHelper {
25  	private static class Day {
26  		public Day(String date, String day, long time) {
27  			this.date = date;
28  			this.wday = day;
29  			this.time = time;
30  		}
31  
32  		public final String date;
33  		public final String wday;
34  		public final long time;
35  	}
36  
37  	public static final int MILLIS_PER_SECOND = 1000;
38  	public static final int MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
39  	public static final int MILLIS_PER_FIVE_MINUTE = 5 * 60 * MILLIS_PER_SECOND;
40  	public static final int MILLIS_PER_TEN_MINUTE = 10 * MILLIS_PER_MINUTE;
41  	public static final int MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
42  	public static final int MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
43  
44  	private DateTimeHelper(TimeZone zone) {
45  		try {
46  			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
47  			sdf.setTimeZone(zone);
48  			BASE_TIME = sdf.parse("20000101").getTime();
49  			open();
50  		} catch (Exception e) {
51  			e.printStackTrace();
52  		}
53  	}
54  
55  	static String wday[] = { "Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun" };
56  	static int mdayLen[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
57  
58  	private long BASE_TIME;
59  	private Day[][][] table = new Day[100][][];
60  	private Day[] dateTable = new Day[40000];
61  
62  	public long getBaseTime() {
63  		return BASE_TIME;
64  	}
65  
66  	private void open() throws Exception {
67  		long mtime = BASE_TIME;
68  		int seq = 0;
69  		int wdayIdx = 5;// 20000101:Saturday
70  		for (int year = 0; year < 100; year++) {
71  			boolean isYun = isYun(year);
72  			table[year] = new Day[12][];
73  			for (int mm = 0; mm < 12; mm++) {
74  				int monLen = mdayLen[mm];
75  				if (mm == 1 && isYun) {
76  					monLen++;
77  				}
78  				table[year][mm] = new Day[monLen];
79  				for (int dd = 0; dd < monLen; dd++) {
80  					String yyyyMMdd = String.format("%d%02d%02d", (year + 2000), mm + 1, dd + 1);
81  
82  					dateTable[seq] = new Day(yyyyMMdd, wday[wdayIdx], mtime);
83  					table[year][mm][dd] = dateTable[seq];
84  
85  					wdayIdx = wdayIdx == 6 ? 0 : wdayIdx + 1;
86  					seq++;
87  					mtime += MILLIS_PER_DAY;
88  				}
89  			}
90  		}
91  
92  	}
93  
94  	static boolean isYun(int year) {
95  		if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
96  			return true;
97  		else
98  			return false;
99  	}
100 
101 	public long yyyymmdd(String yyyyMMdd) {
102 		int year = Integer.parseInt(yyyyMMdd.substring(0, 4));
103 		int mm = Integer.parseInt(yyyyMMdd.substring(4, 6));
104 		int dd = Integer.parseInt(yyyyMMdd.substring(6, 8));
105 		if (year >= 2100)
106 			return table[99][11][30].time + MILLIS_PER_DAY;
107 		if (year < 2000)
108 			return BASE_TIME;
109 		return table[year - 2000][mm - 1][dd - 1].time;
110 	}
111 
112 	public long hhmm(String date) {
113 		if (date == null)
114 			return 0;
115 		int h = Integer.parseInt(date.substring(0, 2));
116 		int m = Integer.parseInt(date.substring(2, 4));
117 		return h * MILLIS_PER_HOUR + m * MILLIS_PER_MINUTE;
118 	}
119 
120 	public String getWeekDay(String yyyyMMdd) {
121 		int year = Integer.parseInt(yyyyMMdd.substring(0, 4));
122 		int mm = Integer.parseInt(yyyyMMdd.substring(4, 6));
123 		int dd = Integer.parseInt(yyyyMMdd.substring(6, 8));
124 		if (year >= 2100)
125 			return table[99][11][30].wday;
126 		if (year < 2000)
127 			return table[0][0][0].wday;
128 		return table[year - 2000][mm - 1][dd - 1].wday;
129 	}
130 
131 	public String yyyymmdd(long time) {
132 		int idx = (int) ((time - BASE_TIME) / MILLIS_PER_DAY);
133 		if (idx < 0)
134 			idx = 0;
135 		return dateTable[idx].date;
136 	}
137 
138 	public String datetime(long time) {
139 		if (time < BASE_TIME)
140 			return "20000101 00:00:00";
141 		int idx = (int) ((time - BASE_TIME) / MILLIS_PER_DAY);
142 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
143 		int hh = (int) (dtime / MILLIS_PER_HOUR);
144 		dtime = (int) (dtime % MILLIS_PER_HOUR);
145 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
146 		dtime = (int) (dtime % MILLIS_PER_MINUTE);
147 		int ss = (int) (dtime / MILLIS_PER_SECOND);
148 
149 		StringBuffer sb = new StringBuffer();
150 		sb.append(dateTable[idx].date).append(" ");
151 		sb.append(mk2(hh)).append(":");
152 		sb.append(mk2(mm)).append(":");
153 		sb.append(mk2(ss));
154 		return sb.toString();
155 	}
156 
157 	public String timestamp(long time) {
158 		if (time < BASE_TIME)
159 			return "20000101 00:00:00.000";
160 		int idx = (int) ((time - BASE_TIME) / MILLIS_PER_DAY);
161 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
162 		int hh = (int) (dtime / MILLIS_PER_HOUR);
163 		dtime = (int) (dtime % MILLIS_PER_HOUR);
164 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
165 		dtime = (int) (dtime % MILLIS_PER_MINUTE);
166 		int ss = (int) (dtime / MILLIS_PER_SECOND);
167 		int sss = (int) (dtime % 1000);
168 
169 		StringBuffer sb = new StringBuffer();
170 		sb.append(dateTable[idx].date).append(" ");
171 		sb.append(mk2(hh)).append(":");
172 		sb.append(mk2(mm)).append(":");
173 		sb.append(mk2(ss));
174 		sb.append(".").append(mk3(sss));
175 		return sb.toString();
176 
177 	}
178 
179 	private String mk2(int n) {
180 		switch (n) {
181 		case 0:
182 		case 1:
183 		case 2:
184 		case 3:
185 		case 4:
186 		case 5:
187 		case 6:
188 		case 7:
189 		case 8:
190 		case 9:
191 			return "0" + n;
192 		default:
193 			return Integer.toString(n);
194 		}
195 	}
196 
197 	private String mk3(int n) {
198 		switch (n) {
199 		case 0:
200 		case 1:
201 		case 2:
202 		case 3:
203 		case 4:
204 		case 5:
205 		case 6:
206 		case 7:
207 		case 8:
208 		case 9:
209 			return "00" + n;
210 		default:
211 			return n < 100 ? "0" + n : Integer.toString(n);
212 		}
213 	}
214 
215 	public String timestampFileName(long time) {
216 		if (time < BASE_TIME)
217 			return "20000101_000000_000";
218 		int idx = (int) ((time - BASE_TIME) / MILLIS_PER_DAY);
219 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
220 		int hh = (int) (dtime / MILLIS_PER_HOUR);
221 		dtime = (int) (dtime % MILLIS_PER_HOUR);
222 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
223 		dtime = (int) (dtime % MILLIS_PER_MINUTE);
224 		int ss = (int) (dtime / MILLIS_PER_SECOND);
225 		int sss = (int) (dtime % 1000);
226 		StringBuffer sb = new StringBuffer();
227 		sb.append(dateTable[idx].date).append("_");
228 		sb.append(mk2(hh));
229 		sb.append(mk2(mm));
230 		sb.append(mk2(ss));
231 		sb.append("_").append(mk3(sss));
232 		return sb.toString();
233 
234 	}
235 
236 	public String ymdhms(long time) {
237 		if (time < BASE_TIME)
238 			return "20000101000000";
239 		int idx = (int) ((time - BASE_TIME) / MILLIS_PER_DAY);
240 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
241 		int hh = (int) (dtime / MILLIS_PER_HOUR);
242 		dtime = (int) (dtime % MILLIS_PER_HOUR);
243 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
244 		dtime = (int) (dtime % MILLIS_PER_MINUTE);
245 		int ss = (int) (dtime / MILLIS_PER_SECOND);
246 		StringBuffer sb = new StringBuffer();
247 		sb.append(dateTable[idx].date);
248 		sb.append(mk2(hh));
249 		sb.append(mk2(mm));
250 		sb.append(mk2(ss));
251 		return sb.toString();
252 	}
253 
254 	public String logtime(long time) {
255 		if (time < BASE_TIME)
256 			return "00:00:00.000";
257 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
258 		int hh = (int) (dtime / MILLIS_PER_HOUR);
259 		dtime = (int) (dtime % MILLIS_PER_HOUR);
260 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
261 		dtime = (int) (dtime % MILLIS_PER_MINUTE);
262 		int ss = (int) (dtime / MILLIS_PER_SECOND);
263 		int sss = (int) (dtime % 1000);
264 		StringBuffer sb = new StringBuffer();
265 		sb.append(mk2(hh)).append(":");
266 		sb.append(mk2(mm)).append(":");
267 		sb.append(mk2(ss));
268 		sb.append(".").append(mk3(sss));
269 		return sb.toString();
270 	}
271 
272 	public String hhmmss(long time) {
273 		if (time < BASE_TIME)
274 			return "000000";
275 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
276 		int hh = (int) (dtime / MILLIS_PER_HOUR);
277 		dtime = (int) (dtime % MILLIS_PER_HOUR);
278 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
279 		dtime = (int) (dtime % MILLIS_PER_MINUTE);
280 		int ss = (int) (dtime / MILLIS_PER_SECOND);
281 		return String.format("%02d%02d%02d", hh, mm, ss);
282 	}
283 
284 	public String hhmm(long time) {
285 		if (time < BASE_TIME)
286 			return "0000";
287 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
288 		int hh = (int) (dtime / MILLIS_PER_HOUR);
289 		dtime = (int) (dtime % MILLIS_PER_HOUR);
290 		int mm = (int) (dtime / MILLIS_PER_MINUTE);
291 
292 		return String.format("%02d%02d", hh, mm);
293 	}
294 
295 	public int getDateMillis(long time) {
296 		if (time < BASE_TIME)
297 			return 0;
298 		long dtime = (time - BASE_TIME) % MILLIS_PER_DAY;
299 		return (int) dtime;
300 	}
301 
302 	public int getHour(long time) {
303 		return getDateMillis(time) / MILLIS_PER_HOUR;
304 	}
305 
306 	public int getMM(long time) {
307 		int dtime = getDateMillis(time) % MILLIS_PER_HOUR;
308 		return (dtime / MILLIS_PER_MINUTE);
309 	}
310 
311 	public long getTimeUnit(long time) {
312 		return (time - BASE_TIME);
313 	}
314 
315 	public long getDateUnit(long time) {
316 		return (time - BASE_TIME) / MILLIS_PER_DAY;
317 	}
318 
319 	public long getTenMinUnit(long time) {
320 		return (time - BASE_TIME) / MILLIS_PER_TEN_MINUTE;
321 	}
322 
323 	public long getMinUnit(long time) {
324 		return (time - BASE_TIME) / MILLIS_PER_MINUTE;
325 	}
326 
327 	public long getHourUnit(long time) {
328 		return (time - BASE_TIME) / MILLIS_PER_HOUR;
329 	}
330 
331 	public long reverseHourUnit(long unit) {
332 		return (unit * MILLIS_PER_HOUR) + BASE_TIME;
333 	}
334 
335 	public long getDateUnit() {
336 		return getDateUnit(System.currentTimeMillis());
337 	}
338 
339 	private static StringKeyLinkedMap<DateTimeHelper> _table = new StringKeyLinkedMap<DateTimeHelper>().setMax(5);
340 
341 	public static DateTimeHelper getDefault() {
342 		return getDateTimeHelper(TimeZone.getDefault());
343 	}
344 
345 	public static synchronized DateTimeHelper getDateTimeHelper(TimeZone timezone) {
346 		DateTimeHelper helper = _table.get(timezone.getID());
347 		if (helper == null) {
348 			helper = new DateTimeHelper(timezone);
349 			;
350 			_table.put(timezone.getID(), helper);
351 		}
352 		return helper;
353 	}
354 
355 	public long xxx() {
356 		return -10956L * MILLIS_PER_DAY + BASE_TIME;
357 	}
358 
359 	public static void main(String[] args) throws Exception {
360 
361 		System.out.println(new Timestamp(DateTimeHelper.getDefault().xxx()));
362 		System.out.println(DateTimeHelper.getDefault().yyyymmdd(0));
363 	}
364 
365 	private static void c1(DateTimeHelper dh) throws ParseException {
366 		long t1 = new SimpleDateFormat("yyyyMMdd").parse("20000101").getTime();
367 		long t2 = dh.yyyymmdd("20000101");
368 		System.out.println(t1);
369 		System.out.println(t2);
370 	}
371 
372 	private static void c2(DateTimeHelper dh) throws ParseException {
373 		long t1 = new SimpleDateFormat("yyyyMMddHHmm").parse("201502241212").getTime();
374 		long t2 = dh.yyyymmdd("20150224") + dh.hhmm("1212");
375 		System.out.println(t1);
376 		System.out.println(t2);
377 	}
378 
379 }